import datetime
import time
from common import (
    lib60870, ctypes,
    CS101_CauseOfTransmission, QualifierOfInterrogation, CS104_ConnectionEvent,
    CP56Time2aStruct, ASDUReceivedHandler
)

# 主站特有函数封装
class CS104Client:
    def __init__(self, hostname: str, tcp_port: int = -1):
        self.hostname = hostname.encode('utf-8')
        self.tcp_port = tcp_port
        self.connection = None
        self.asdu_handler = None
        self.connection_handler = None

        # 初始化连接函数原型
        self._init_library_functions()

    def _init_library_functions(self):
        """初始化主站相关库函数原型"""
        # 创建连接
        lib60870.CS104_Connection_create.argtypes = [ctypes.c_char_p, ctypes.c_int]
        lib60870.CS104_Connection_create.restype = ctypes.c_void_p

        # 安全连接（TLS）
        # lib60870.CS104_Connection_createSecure.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]
        # lib60870.CS104_Connection_createSecure.restype = ctypes.c_void_p

        # 连接
        lib60870.CS104_Connection_connect.argtypes = [ctypes.c_void_p]
        lib60870.CS104_Connection_connect.restype = ctypes.c_bool

        # 异步连接
        lib60870.CS104_Connection_connectAsync.argtypes = [ctypes.c_void_p]
        lib60870.CS104_Connection_connectAsync.restype = None

        # 发送StartDT
        lib60870.CS104_Connection_sendStartDT.argtypes = [ctypes.c_void_p]
        lib60870.CS104_Connection_sendStartDT.restype = None

        # 发送StopDT
        lib60870.CS104_Connection_sendStopDT.argtypes = [ctypes.c_void_p]
        lib60870.CS104_Connection_sendStopDT.restype = None

        # 设置ASDU接收回调
        lib60870.CS104_Connection_setASDUReceivedHandler.argtypes = [
            ctypes.c_void_p, ASDUReceivedHandler, ctypes.c_void_p
        ]
        lib60870.CS104_Connection_setASDUReceivedHandler.restype = None

        # 发送 interrogation 命令
        lib60870.CS104_Connection_sendInterrogationCommand.argtypes = [
            ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib60870.CS104_Connection_sendInterrogationCommand.restype = ctypes.c_bool

        # 发送时钟同步命令
        lib60870.CS104_Connection_sendClockSyncCommand.argtypes = [
            ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(CP56Time2aStruct)  # 第三个参数改为指针
        ]
        lib60870.CS104_Connection_sendClockSyncCommand.restype = ctypes.c_bool

        # 发送读命令
        lib60870.CS104_Connection_sendReadCommand.argtypes = [
            ctypes.c_void_p, ctypes.c_int, ctypes.c_int
        ]
        lib60870.CS104_Connection_sendReadCommand.restype = ctypes.c_bool

        # 检查发送缓冲区是否满
        lib60870.CS104_Connection_isTransmitBufferFull.argtypes = [ctypes.c_void_p]
        lib60870.CS104_Connection_isTransmitBufferFull.restype = ctypes.c_bool

    def connect(self, blocking: bool = True) -> bool:
        """创建并连接到服务器"""
        self.connection = lib60870.CS104_Connection_create(self.hostname, self.tcp_port)
        if not self.connection:
            return False

        if blocking:
            return lib60870.CS104_Connection_connect(self.connection)
        else:
            lib60870.CS104_Connection_connectAsync(self.connection)
            return True

    def connect_secure(self, tls_config, blocking: bool = True) -> bool:
        """创建并连接到服务器（TLS加密）"""
        self.connection = lib60870.CS104_Connection_createSecure(
            self.hostname, self.tcp_port, tls_config
        )
        if not self.connection:
            return False

        if blocking:
            return lib60870.CS104_Connection_connect(self.connection)
        else:
            lib60870.CS104_Connection_connectAsync(self.connection)
            return True

    def start_data_transmission(self):
        """开始数据传输"""
        if self.connection:
            lib60870.CS104_Connection_sendStartDT(self.connection)

    def stop_data_transmission(self):
        """停止数据传输"""
        if self.connection:
            lib60870.CS104_Connection_sendStopDT(self.connection)

    def set_asdu_received_handler(self, handler):
        """设置ASDU接收回调函数"""
        if not self.connection:
            raise Exception("未建立连接")

        self.asdu_handler = ASDUReceivedHandler(handler)
        lib60870.CS104_Connection_setASDUReceivedHandler(
            self.connection, self.asdu_handler, None
        )

    def send_interrogation(self, cot: CS101_CauseOfTransmission, ca: int, 
                          qoi: QualifierOfInterrogation) -> bool:
        """发送总召唤命令"""
        if not self.connection:
            return False

        return lib60870.CS104_Connection_sendInterrogationCommand(
            self.connection, cot.value, ca, qoi.value
        )

    def send_clock_sync(self, ca: int, dt: datetime.datetime) -> bool:
        """发送时钟同步命令（修复指针传递问题）"""
        if not self.connection:
            return False

        cp_time = CP56Time2aStruct.from_datetime(dt)
        # 传递结构体的指针（byref获取指针）
        return lib60870.CS104_Connection_sendClockSyncCommand(
            self.connection, ca, ctypes.byref(cp_time)
        )

    def send_read_command(self, ca: int, ioa: int) -> bool:
        """发送读命令"""
        if not self.connection:
            return False

        return lib60870.CS104_Connection_sendReadCommand(self.connection, ca, ioa)

    def is_transmit_buffer_full(self) -> bool:
        """检查发送缓冲区是否满"""
        if not self.connection:
            return True
        return lib60870.CS104_Connection_isTransmitBufferFull(self.connection)

    def close(self):
        """关闭连接，确保参数有效"""
        if self.connection is not None:
            if hasattr(lib60870, "CS104_Connection_close"):
                try:
                    if isinstance(self.connection, ctypes.c_void_p):
                        lib60870.CS104_Connection_close(self.connection)
                    else:
                        lib60870.CS104_Connection_close(ctypes.c_void_p(self.connection))
                except Exception as e:
                    print(f"关闭连接时出错: {e}")
            self.connection = None

    def __del__(self):
        """析构函数，确保连接关闭"""
        self.close()


# 使用示例
if __name__ == "__main__":
    def asdu_received_handler(parameter, asdu):
        """ASDU接收回调示例"""
        asdu_hex = f"0x{asdu:X}" if asdu is not None else "None"
        print(f"收到ASDU: {asdu_hex} {asdu}")

    # 创建客户端并连接
    client = CS104Client("127.0.0.1", 2404)
    if client.connect():
        print("连接成功")
        
        # 设置ASDU接收回调
        client.set_asdu_received_handler(asdu_received_handler)
        
        # 开始数据传输
        client.start_data_transmission()
        
        # 发送总召唤
        client.send_interrogation(
            CS101_CauseOfTransmission.ACTIVATION,
            1,  # 公共地址
            QualifierOfInterrogation.STATION_INTERROGATION
        )
        
        # 发送时钟同步
        client.send_clock_sync(1, datetime.datetime.now())
        
        # 等待一段时间接收数据
        time.sleep(10)
        
        # 停止数据传输
        client.stop_data_transmission()
        
        # 关闭连接
        client.close()
    else:
        print("连接失败")